package com.thbent.alarm.timer;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javafish.clients.opc.JOpc;
import javafish.clients.opc.component.OpcGroup;
import javafish.clients.opc.component.OpcItem;
import javafish.clients.opc.exception.ComponentNotFoundException;
import javafish.clients.opc.exception.ConnectivityException;
import javafish.clients.opc.exception.SynchReadException;
import javafish.clients.opc.exception.UnableAddGroupException;
import javafish.clients.opc.exception.UnableAddItemException;
import javafish.clients.opc.variant.Variant;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import com.thbent.alarm.exception.AlarmException;
import com.thbent.alarm.model.AlarmData;
import com.thbent.alarm.model.CountData;
import com.thbent.alarm.model.Parameter;
import com.thbent.alarm.model.PhoneAndProbe;
import com.thbent.alarm.model.Probe;
import com.thbent.alarm.port.ReadSerialPort;
import com.thbent.alarm.service.AlarmDataService;
import com.thbent.alarm.service.CountDataService;
import com.thbent.alarm.service.ParameterService;
import com.thbent.alarm.service.PhoneAndProbeService;
import com.thbent.alarm.service.ProbeService;
import com.thbent.alarm.utils.Constant;

@Component
public class ReadData {

	private static final Logger LOGGER = LogManager.getLogger("ReadData");

	@Autowired
	private ProbeService probeService;
	@Autowired
	private AlarmDataService alarmDataService;
	@Autowired
	private CountDataService countDataService;
	@Autowired
	private ParameterService parameterService;
	@Autowired
	private PhoneAndProbeService phoneAndProbeService;

	@Scheduled(cron = "0 0/1 * * * *")
	public void getData() {
		LOGGER.debug("---------------timer start ------------------");

		// 第一步，初始化
		// 把配置文件javafish/clients/opc/JCustomOpc.properties、放到classpath
		JOpc.coInitialize();
		// 第二步，建立一个JOpc对象，三个参数，分别是OpcServer的IP，Server的name，还有JOpc的name
		JOpc jopc = new JOpc("127.0.0.1", "PCAuto.OPCServer", "JOPC1");
		// 第三步，建立连接
		try {
			jopc.connect();
		} catch (ConnectivityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		// 第四步，新建一个OPC的group和item，并把item加到group中
		OpcGroup group = new OpcGroup("TestGroup", true, 500, 0.0f);
		for (int i = 1; i <= 22; i++) {
			StringBuffer itemName = new StringBuffer("F0\\MT");
			itemName.append(i + ".pv");
			OpcItem item = new OpcItem(itemName.toString(), true, "");
			group.addItem(item);
		}
		// 第五步，注册group，item
		jopc.addGroup(group);
		try {
			jopc.registerGroups();
		} catch (ComponentNotFoundException | UnableAddGroupException e) {
			e.printStackTrace();
		} catch (UnableAddItemException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		synchronized (ReadData.class) {
			try {
				ReadData.class.wait(2000);
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
		OpcGroup responseGroup = null;
		try {
			responseGroup = jopc.synchReadGroup(group);
		} catch (ComponentNotFoundException | SynchReadException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		System.out.println(responseGroup.getItems());
		ArrayList<OpcItem> opcItems = responseGroup.getItems();
		for (OpcItem opcItem : opcItems) {
			Variant var = opcItem.getValue();
			double value = var.getDouble();
			System.out.println(value + "------");
			System.out
					.println(opcItem.getItemName() + ":" + opcItem.getValue());
		}

		JOpc.coUninitialize();

		List<Probe> probeList = probeService.findAll();
		List<AlarmData> alarmDataList = alarmDataService.findAll();
		CountData countData = new CountData();
		Parameter firstAlarmTime = parameterService
				.findSingleParameter(Constant.PARANMETER_FIRST_ALARM_TIME);
		Parameter repetitionTime = parameterService
				.findSingleParameter(Constant.PARANMETER_REPETITION_TIME);
		int firstAlarmTimeVal = Integer.parseInt(firstAlarmTime.getValue());
		int repetitionTimeVal = Integer.parseInt(repetitionTime.getValue());
		Map<String, List<String>> phoneMap = getPhoneNo();
		ReadSerialPort readSerialPort = ReadSerialPort.get();
		for (Probe probe : probeList) {
			String tagName = probe.getTagName();
			List<String> phoneList = phoneMap.get(tagName);
			int count = probe.getCount();
			countData.setName(tagName);
			AlarmData alarmData;
			try {
				alarmData = getAlarmData(alarmDataList,
						probe.getStorageRoomId());
				if (tagName.startsWith("T")) {
					temperatureAlarm(alarmData, countData, readSerialPort,
							probe, tagName, count, phoneList,
							firstAlarmTimeVal, repetitionTimeVal);
				} else {
					humidityAlarm(alarmData, countData, readSerialPort, probe,
							count, phoneList, firstAlarmTimeVal,
							repetitionTimeVal);
				}
			} catch (AlarmException e) {
				LOGGER.error(e.getMessage(), e);
			}
		}
		LOGGER.debug("---------------timer end ------------------");
	}

	/**
	 * 获取报警参数
	 * 
	 * @param alarmDataList
	 * @param storageRoomId
	 * @return
	 * @throws AlarmException
	 */
	private AlarmData getAlarmData(List<AlarmData> alarmDataList,
			String storageRoomId) throws AlarmException {
		for (AlarmData alarmData : alarmDataList) {
			if (storageRoomId.equals(alarmData.getStorageRoomId())) {
				return alarmData;
			}
		}
		throw new AlarmException(storageRoomId + "没有报警数据");
	}

	private Map<String, List<String>> getPhoneNo() {
		Map<String, List<String>> PhoneNoMap = new HashMap<String, List<String>>();
		List<Parameter> phoneList = parameterService
				.findParametersByName(Constant.PARANMETER_PHONE);
		List<PhoneAndProbe> phoneAndProbeList = phoneAndProbeService.findAll();
		for (PhoneAndProbe phoneAndProbe : phoneAndProbeList) {
			ArrayList<String> phoneNoList = new ArrayList<String>();
			PhoneNoMap.put(phoneAndProbe.getProbeName(), phoneNoList);
			for (Parameter parameter : phoneList) {
				if (phoneAndProbe.getPhoneId().equals(parameter.getId())) {
					phoneNoList.add(parameter.getValue());
				}
			}
		}
		return PhoneNoMap;
	}

	/**
	 * 温度报警
	 * 
	 * @param alarmData
	 * @param countData
	 * @param readSerialPort
	 * @param probe
	 * @param tagName
	 * @param count
	 * @param phoneList
	 * @param firstAlarmTimeVal
	 * @param repetitionTimeVal
	 */
	private void temperatureAlarm(AlarmData alarmData, CountData countData,
			ReadSerialPort readSerialPort, Probe probe, String tagName,
			int count, List<String> phoneList, int firstAlarmTimeVal,
			int repetitionTimeVal) {
		if (phoneList != null) {
			if (probe.getPv() > alarmData.getMaxValue()) {// 温度过高
				overTopAlarm(alarmData, countData, readSerialPort, probe,
						count, phoneList, firstAlarmTimeVal, repetitionTimeVal,
						"温度");
			} else if (probe.getPv() < alarmData.getMinValue()) {// 温度过低
				tooLowAlarm(alarmData, countData, readSerialPort, probe, count,
						phoneList, firstAlarmTimeVal, repetitionTimeVal, "温度");
			} else {
				otherAlarm(countData, count);
			}
		}
	}

	/**
	 * 湿度报警
	 * 
	 * @param alarmData
	 * @param countData
	 * @param readSerialPort
	 * @param probe
	 * @param count
	 * @param phoneList
	 * @param firstAlarmTimeVal
	 * @param repetitionTimeVal
	 */
	private void humidityAlarm(AlarmData alarmData, CountData countData,
			ReadSerialPort readSerialPort, Probe probe, int count,
			List<String> phoneList, int firstAlarmTimeVal, int repetitionTimeVal) {
		if (phoneList != null) {
			if (probe.getPv() > alarmData.getMaxValue()) {// 湿度过高
				overTopAlarm(alarmData, countData, readSerialPort, probe,
						count, phoneList, firstAlarmTimeVal, repetitionTimeVal,
						"湿度");
			} else if (probe.getPv() < alarmData.getMinValue()) {// 湿度过低
				tooLowAlarm(alarmData, countData, readSerialPort, probe, count,
						phoneList, firstAlarmTimeVal, repetitionTimeVal, "湿度");
			} else {
				otherAlarm(countData, count);
			}
		}
	}

	/**
	 * 过低报警
	 * 
	 * @param alarmData
	 * @param countData
	 * @param readSerialPort
	 * @param probe
	 * @param count
	 * @param phoneList
	 * @param firstAlarmTimeVal
	 * @param repetitionTimeVal
	 * @param AlarmMessage
	 */
	private void tooLowAlarm(AlarmData alarmData, CountData countData,
			ReadSerialPort readSerialPort, Probe probe, int count,
			List<String> phoneList, int firstAlarmTimeVal,
			int repetitionTimeVal, String AlarmMessage) {
		for (String phone : phoneList) {
			String message = "AT+SMS=" + phone + " "
					+ probe.getStorageRoomName() + "设备"
					+ probe.getNameInStroageRoom() + AlarmMessage + "过低，"
					+ AlarmMessage + "下限为" + alarmData.getMaxValue() + "当前"
					+ AlarmMessage + "为" + probe.getPv() + "\r\n";
			alarm(countData, readSerialPort, count, message, firstAlarmTimeVal,
					repetitionTimeVal);
		}
	}

	/**
	 * 过高报警
	 * 
	 * @param alarmData
	 * @param countData
	 * @param readSerialPort
	 * @param probe
	 * @param count
	 * @param phoneList
	 * @param firstAlarmTimeVal
	 * @param repetitionTimeVal
	 */
	private void overTopAlarm(AlarmData alarmData, CountData countData,
			ReadSerialPort readSerialPort, Probe probe, int count,
			List<String> phoneList, int firstAlarmTimeVal,
			int repetitionTimeVal, String alarmMessage) {
		for (String phone : phoneList) {
			String message = "AT+SMS=" + phone + " "
					+ probe.getStorageRoomName() + "设备"
					+ probe.getNameInStroageRoom() + alarmMessage + "过高，"
					+ alarmMessage + "上限为" + alarmData.getMaxValue() + "当前"
					+ alarmMessage + "为" + probe.getPv() + "\r\n";

			alarm(countData, readSerialPort, count, message, firstAlarmTimeVal,
					repetitionTimeVal);
		}
	}

	private void otherAlarm(CountData countData, int count) {
		if (count != 0) {
			countData.setCount(0);
			countDataService.modifyCount(countData);
		}
	}

	/**
	 * 报警
	 * 
	 * @param countData
	 * @param readSerialPort
	 * @param count
	 * @param message
	 * @param firstAlarmTimeVal
	 * @param repetitionTimeVal
	 */
	private void alarm(CountData countData, ReadSerialPort readSerialPort,
			int count, String message, int firstAlarmTimeVal,
			int repetitionTimeVal) {
		count++;
		if (count == firstAlarmTimeVal) {
			readSerialPort.sendMessage(message);
		} else if (count > firstAlarmTimeVal
				&& (count - firstAlarmTimeVal) % repetitionTimeVal == 0) {
			readSerialPort.sendMessage(message);
		}
		countData.setCount(count);
		countDataService.modifyCount(countData);
	}
}
